package cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.resources.follow;

import cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.auth.annotation.Auth;
import cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.auth.configrations.AuthResolver;
import cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.resources.practiseDiary.PractiseDiaryDto;
import cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.resources.practiseDiary.PractiseDiaryResourceAssembler;
import cn.thoughtworks.school.pactise.diary.application.gateway.user.UserDto;
import cn.thoughtworks.school.pactise.diary.application.gateway.user.UserService;
import cn.thoughtworks.school.pactise.diary.application.usecases.comment.QueryCommentUseCase;
import cn.thoughtworks.school.pactise.diary.application.usecases.follow.EditFollowUseCase;
import cn.thoughtworks.school.pactise.diary.application.usecases.follow.QueryFollowUseCase;
import cn.thoughtworks.school.pactise.diary.application.usecases.practiseDiary.QueryPractiseDiaryUseCase;
import cn.thoughtworks.school.pactise.diary.domain.context.practiseDiaryContext.follow.Follow;
import cn.thoughtworks.school.pactise.diary.domain.context.practiseDiaryContext.practiseDiary.PractiseDiary;
import cn.thoughtworks.school.pactise.diary.domain.context.practiseDiaryContext.practiseDiary.PractiseDiaryCount;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@RestController
@RequestMapping(value = "/api/followees")
public class FollowResource {
    private final QueryFollowUseCase queryFollowUseCase;
    private final EditFollowUseCase editFollowUseCase;
    private final QueryPractiseDiaryUseCase queryPractiseDiaryUseCase;
    private final UserService userService;
    private final PractiseDiaryResourceAssembler practiseDiaryResourceAssembler;
    private final QueryCommentUseCase queryCommentUseCase;

    public FollowResource(QueryFollowUseCase queryFollowUseCase, EditFollowUseCase editFollowUseCase, QueryPractiseDiaryUseCase queryPractiseDiaryUseCase, UserService userService, PractiseDiaryResourceAssembler practiseDiaryResourceAssembler, QueryCommentUseCase queryCommentUseCase) {
        this.queryFollowUseCase = queryFollowUseCase;
        this.editFollowUseCase = editFollowUseCase;
        this.queryPractiseDiaryUseCase = queryPractiseDiaryUseCase;
        this.userService = userService;
        this.practiseDiaryResourceAssembler = practiseDiaryResourceAssembler;
        this.queryCommentUseCase = queryCommentUseCase;
    }

    @RequestMapping(value = "/searching", method = RequestMethod.GET)
    public ResponseEntity<List<UserDto>> searchingFollowees(@Auth AuthResolver.User user, @RequestParam(value = "nameOrEmail") String nameOrEmail) {
        List<UserDto> users = userService.getUserByUserNameOrEmail(nameOrEmail);

        users.forEach(item -> {
            Long followeeId = Long.parseLong(item.getId().toString());
            Follow existUser = queryFollowUseCase.findByFollowerIdAndFolloweeId(user.getId(), followeeId);
            item.setFollowed(existUser != null);
        });

        return new ResponseEntity<>(users, HttpStatus.OK);
    }

    @RequestMapping(value = "/{followeeId}", method = RequestMethod.POST)
    public ResponseEntity createFollow(@Auth AuthResolver.User user, @PathVariable Long followeeId) {
        Follow follow = queryFollowUseCase.findByFollowerIdAndFolloweeId(user.getId(), followeeId);
        if (follow != null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        follow = new Follow(user.getId(), followeeId, simpleDateFormat.format(now));

        follow = editFollowUseCase.save(follow);
        return new ResponseEntity<>(follow.getId(), HttpStatus.CREATED);
    }

    @RequestMapping(value = "/{followeeId}", method = RequestMethod.DELETE)
    public ResponseEntity deleteFollow(@Auth AuthResolver.User user, @PathVariable Long followeeId) {
        Follow follow = queryFollowUseCase.findByFollowerIdAndFolloweeId(user.getId(), followeeId);
        if (follow != null) {
            editFollowUseCase.deleteById(follow.getId());
        }
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    @RequestMapping(value = "", method = RequestMethod.GET)
    public ResponseEntity<List<PractiseDiaryWithContactDto>> getContactList(@Auth AuthResolver.User user) {
        List<Follow> follows = queryFollowUseCase.findByFollowerId(user.getId());

        List<PractiseDiaryWithContactDto> diariesAndContactInfoList = new ArrayList<>();
        for (Follow follow : follows) {
            List<PractiseDiary> practiseDiaryList = queryPractiseDiaryUseCase.findByAuthorIdOrderByDateDesc(follow.getFolloweeId());
            UserDto userInfo = userService.getDiaryAuthorInfo(follow.getFolloweeId());
            diariesAndContactInfoList.add(new PractiseDiaryWithContactDto(practiseDiaryList, userInfo));
        }
        return new ResponseEntity<>(diariesAndContactInfoList, HttpStatus.OK);
    }


    @RequestMapping(value = "/{followeeId}/practise-diaries", method = RequestMethod.GET, params = {"page", "pageSize"})
    public ResponseEntity getContactUserDiariesAndComments(@Auth AuthResolver.User user, @PathVariable Long followeeId, @RequestParam(value = "page", defaultValue = "1") int page, @RequestParam(value = "pageSize", defaultValue = "20") Integer size) {

        if (hasFollowRelationship(user, followeeId)) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }
        Sort sort = new Sort(Sort.Direction.DESC, "Date");
        Pageable pageable = PageRequest.of(page - 1, size, sort);

        List<PractiseDiary> practiseDiaryList = queryPractiseDiaryUseCase.findByAuthorId(followeeId, pageable);
        List<PractiseWithCommentsDto> practiseAndCommentsList = queryCommentUseCase.attachComments(practiseDiaryList);

        UserDto followeeInfo = userService.getDiaryAuthorInfo(followeeId);
        int total = (queryPractiseDiaryUseCase.findByAuthorIdOrderByDateDesc(followeeId)).size();

        return new ResponseEntity<>(new FolloweePractiseDiaryWithCommentsDto(total, practiseAndCommentsList, followeeInfo), HttpStatus.OK);
    }

    @RequestMapping(value = "/{followeeId}/practise-diaries", method = RequestMethod.GET, params = {"year", "month"})
    public ResponseEntity<List<PractiseDiaryDto>> getMonthlyDiaryByAuthorId(@Auth AuthResolver.User user,
                                                                            @PathVariable Long followeeId,
                                                                            @RequestParam(value = "year") int year,
                                                                            @RequestParam(value = "month") int month) {

        if (hasFollowRelationship(user, followeeId)) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }
        List<PractiseDiary> practiseDiaries = queryPractiseDiaryUseCase.findMonthlyDiariesByAuthorId(followeeId, year, month);

        List<PractiseDiaryDto> practiseDiaryResources = practiseDiaryResourceAssembler.toResources(practiseDiaries);

        return new ResponseEntity<>(practiseDiaryResources, HttpStatus.OK);
    }

    private boolean hasFollowRelationship(AuthResolver.User user, Long followeeId) {
        Follow follow = queryFollowUseCase.findByFollowerIdAndFolloweeId(user.getId(), followeeId);
        return follow == null;
    }

    @RequestMapping(value = "/{followeeId}/practise-diaries/monthly-count", method = RequestMethod.GET)
    public ResponseEntity<List<PractiseDiaryCount>> getYearSubmitCountByAuthorId(@Auth AuthResolver.User user,
                                                                                 @PathVariable Long followeeId,
                                                                                 @RequestParam(value = "year") int year) {
        if (hasFollowRelationship(user, followeeId)) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }

        List<PractiseDiaryCount> practiseDiaryCounts = queryPractiseDiaryUseCase.findYearSubmitCountByAuthorId(followeeId, year);


        return new ResponseEntity<>(practiseDiaryCounts, HttpStatus.OK);
    }

    @RequestMapping(value = "/tutors", method = RequestMethod.GET)
    public ResponseEntity getFollowTutors(@Auth AuthResolver.User user) {
        List<Follow> follows = queryFollowUseCase.findByFolloweeId(user.getId());
        List<Long> followerIds = follows.stream().map(Follow::getFollowerId).collect(Collectors.toList());
        List<UserDto> followers = userService.getUsersByIds(followerIds);

        return new ResponseEntity<>(followers, HttpStatus.OK);
    }


}
